package main;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Vector;

import stacking.Stacking;
import utils.DataManipulation;
import weka.classifiers.Classifier;


public class MainStacking {
	
	public static void main(String... args) {
		
//		exemplo de argumentos
//		metaClassifier weka.classifiers.functions.SMO options -C 10 -K "weka.classifiers.functions.supportVector.PolyKernel -E 1" dataset /home/andreybicalho/java_workspace/TP2_MachineLearning/iris.arff baseTrainSplit 40 metaTrainSplit 30 iteracoes 5 baseSettingsPath /home/andreybicalho/java_workspace/TP2_MachineLearning/iris_settings.txt 
		
		// definindo os base classifiers
//		String[] classifier = { "weka.classifiers.trees.J48",
//								"weka.classifiers.rules.ZeroR",
//								"weka.classifiers.bayes.NaiveBayes",
//				                "weka.classifiers.lazy.IBk", 
//				                "weka.classifiers.functions.SMO",
//				                "weka.classifiers.functions.SMO",
//				                "weka.classifiers.functions.SMO"};
//		String[][] baseOptions = {{ "-C", "0.25","-M", "2" },
//								  {""},		
//								  {""},
//				                  {"-K", "5"},
//				                  {"-C", "1","-K","weka.classifiers.functions.supportVector.PolyKernel -E 1"},
//				                  {"-C", "1","-K","weka.classifiers.functions.supportVector.PolyKernel -E 2"},
//				                  {"-C", "1","-K","weka.classifiers.functions.supportVector.RBFKernel -G 0.1"}};
		
		String baseSettingsPath = "";
		
		String metaClassifier = "weka.classifiers.functions.SMO"; 
		String[] metaOptions = {"-C", "10", "-K","weka.classifiers.functions.supportVector.RBFKernel -G 0.1"};
		//String[] metaOptions = {"-C", "100", "-K","weka.classifiers.functions.supportVector.PolyKernel -E 1"};
		Vector metaclassifierOptions = new Vector();
		
		String dataset_path = "";
		double metaPercentSplit = 50, basePercentSplit = 50;
		int numberOfBaseClassifiers = 7;
		int iteracoes = 1;
		
		int n = 0;
		String current = "";
		boolean newPart = false; 
		do {
			// determine part of command line
			if (args[n].equals("metaClassifier")) {
				current = args[n];
				n++;
				newPart = true;
			} else if (args[n].equals("options")) {
				current = args[n];
				n++;
				newPart = true;
			} else if (args[n].equals("dataset")) {
				current = args[n];
				n++;
				newPart = true;
			} else if(args[n].equals("baseTrainSplit")) {
				current = args[n];
				n++;
				newPart = true;
			} else if(args[n].equals("metaTrainSplit")) {
				current = args[n];
				n++;
				newPart = true;
			} else if(args[n].equals("iteracoes")) {
				current = args[n];
				n++;
				newPart = true;
			} else if(args[n].equals("baseSettingsPath")) {
				current = args[n];
				n++;
				newPart = true;
			}

			
			
			
			if (current.equals("metaClassifier")) {
				if (newPart)
					metaClassifier = args[n];
				else
					metaclassifierOptions.add(args[n]);
			}
			else if(current.equals("options")){
				metaclassifierOptions.add(args[n]);
			}
			else if (current.equals("dataset")) {
				if (newPart)
					dataset_path = args[n];
			}
			else if (current.equals("baseTrainSplit")) {
				if(newPart)
					basePercentSplit = Integer.parseInt(args[n]);
			}
			else if (current.equals("metaTrainSplit")) {
				if(newPart)
					metaPercentSplit = Integer.parseInt(args[n]);
			}
			else if (current.equals("iteracoes")) {
				if(newPart)
					iteracoes = Integer.parseInt(args[n]);
			}
			else if (current.equals("baseSettingsPath")) {
				if(newPart)
					baseSettingsPath = args[n];
			}
			
			// next parameter
			n++;
			newPart = false;
		} while (n < args.length);
		
//		metaClassifier weka.classifiers.trees.J48 options -C 0.25 -M 2 dataset /home/andreybicalho/java_workspace/TP2_MachineLearning/iris.arff baseTrainSplit 40 metaTrainSplit 30
	    		
		metaOptions = (String[])metaclassifierOptions.toArray(new String[metaclassifierOptions.size()]);
		//===========================================================================================================================================
		
//		for(int i=0; i < options1.length;i++){
//			System.out.println(options1[i]);
//		}

		// para guardar a acuracia de cada iteracao (execucao)
		List<Double> acuracia = new ArrayList<Double>();
		
		
			// ===========================================================================================================================================
			// load data
			DataManipulation dataManipulation = new DataManipulation(
					dataset_path, "arff");
			// ===========================================================================================================================================
			// create base classifiers
			dataManipulation.load_baseClassifiers_settings(baseSettingsPath);
			String[] classifier = dataManipulation.getBaseClassifiers();
			String[][] baseOptions = dataManipulation.getBaseClassifiersOptions();
//			System.out.println(baseOptions[0][0]);
			// 
			
			Classifier[] baseClassifiers = new Classifier[numberOfBaseClassifiers];
			for (int i = 0; i < numberOfBaseClassifiers; i++) {
				try {
					baseClassifiers[i] = Classifier.makeCopy(Classifier
							.forName(classifier[i], baseOptions[i]));
				} catch (Exception e) {
					// TODO Auto-generated catch block
					System.out
							.println("error while creating BASE Classifiers on: MainStacking()");
					e.printStackTrace();
				}
			}
			for (int iter = 0; iter < iteracoes; iter++) {
			// ===========================================================================================================================================
			// create stacking meta classifier
			// ===========================================================================================================================================
			Stacking stacking = null;
			try {
				stacking = new Stacking(dataManipulation.getDataset(),
						baseClassifiers, Classifier.forName(metaClassifier,
								metaOptions), basePercentSplit, true);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				System.out
						.println("eror while creating META classifier on: MainStacking()");
				e.printStackTrace();
			}

			stacking.buildStacking(metaPercentSplit);
			// ===========================================================================================================================================
			int trainSize = (int) (stacking.getMetaDataset().numInstances()
					* metaPercentSplit / 100);
			int testSize = stacking.getMetaDataset().numInstances() - trainSize;
			// ===========================================================================================================================================
			// classifying train set
			// ===========================================================================================================================================
			int numCorrect = 0;
			for (int i = 0; i < trainSize; i++) {

				try {
					double pred = stacking.classifyInstance(stacking
							.getMetaDataset().instance(i));
					if (pred == stacking.getMetaDataset().instance(i)
							.classValue())
						numCorrect++;
				} catch (Exception e) {
					// TODO Auto-generated catch block
					System.out
							.println("eror while classifying an instance on: MainStacking()");
					e.printStackTrace();
				}

			}

//			System.out.println("Stacking no treino: " + numCorrect + " de "
//					+ trainSize + " foram classificadas corretamente. ("
//					+ ((double) numCorrect / (double) trainSize * 100) + "%)");
			// ===========================================================================================================================================
			// classifying test set
			// ===========================================================================================================================================
			numCorrect = 0;
			for (int i = trainSize; i < stacking.getMetaDataset()
					.numInstances(); i++) {
				try {
					double pred = stacking.classifyInstance(stacking
							.getMetaDataset().instance(i));
					if (pred == stacking.getMetaDataset().instance(i)
							.classValue())
						numCorrect++;
				} catch (Exception e) {
					// TODO Auto-generated catch block
					System.out
							.println("eror while classifying an instance on: MainStacking()");
					e.printStackTrace();
				}
			}
			acuracia.add((double) numCorrect / (double) testSize * 100);
//			System.out.println("Stacking no teste: " + numCorrect + " de "
//					+ testSize + " foram classificadas corretamente. ("
//					+ ((double) numCorrect / (double) testSize * 100) + "%)");
			
			// ===========================================================================================================================================

		}
			// ===========================================================================================================================================
			// salva
			Double media = new Double(dataManipulation.getMean(acuracia));
			Double stdDev = new Double(dataManipulation.getStdDev(acuracia));
			String pathFile = "meta_" + metaClassifier + "_stacking.txt";
			dataManipulation.save_to_file(media, stdDev, pathFile);
	}
	
	
}
